#include "fontSetter.h"

FontSetter::FontSetter(QWidget *parent)
    : QWidget(parent)
{
    this->firstLineWidget = new QWidget(this);
    this->fontFamilyPicker = new QWidget(this);
    this->fontWeightPicker = new QWidget(this);
    this->fontSizePicker = new QWidget(this);
    this->bottomWidget = new QWidget(this);

    this->fontFamilyLabel = new QLabel(this); this->fontFamilyLabel->setText("Font Family");
    this->fontFamilyInput = new QLineEdit(this);
    this->fontFamilyList = new QListWidget(this);

    this->fontWeightLabel = new QLabel(this); this->fontWeightLabel->setText("Font Weight");
    this->fontWeightInput = new QLineEdit(this->fontWeightPicker);
    this->fontWeightList = new QListWidget(this);

    this->fontSizeLabel = new QLabel(this); this->fontSizeLabel->setText("Font Size");
    this->fontSizeInput = new QLineEdit(this->fontSizePicker);
    this->fontSizeList = new QListWidget(this);

    this->useItalicLabel = new QLabel("Use Italic", this);
    this->useItalicCheckBox = new QCheckBox(this);
    this->confirmButton = new QPushButton(this); this->confirmButton->setText("Confirm");
    this->applyButton = new QPushButton(this); this->applyButton->setText("Apply");
    this->defaultFontButton = new QPushButton(this); this->defaultFontButton->setText("Default Font");
    this->cancelButton = new QPushButton(this); this->cancelButton->setText("Cancel");

    this->fontSizeRegExp = QRegExp("^\\d+(\\.\\d+)?$");
    this->fontSizeInput->setValidator(new QRegExpValidator(this->fontSizeRegExp, this));
    this->fontFamilies = fontDatabase.families();

    // Layout
    this->fontFamilyLayout = new QVBoxLayout();
    this->fontWeightLayout = new QVBoxLayout();
    this->fontSizeLayout = new QVBoxLayout();
    this->bottomLayout = new QHBoxLayout();

    this->fontFamilyLayout->addWidget(this->fontFamilyLabel);
    this->fontFamilyLayout->addWidget(this->fontFamilyInput);
    this->fontFamilyLayout->addWidget(this->fontFamilyList);

    this->fontWeightLayout->addWidget(this->fontWeightLabel);
    this->fontWeightLayout->addWidget(this->fontWeightInput);
    this->fontWeightLayout->addWidget(this->fontWeightList);

    this->fontSizeLayout->addWidget(this->fontSizeLabel);
    this->fontSizeLayout->addWidget(this->fontSizeInput);
    this->fontSizeLayout->addWidget(this->fontSizeList);

    this->bottomLayout->addWidget(this->useItalicLabel);
    this->bottomLayout->addWidget(this->useItalicCheckBox);
    this->bottomLayout->addWidget(this->confirmButton);
    this->bottomLayout->addWidget(this->applyButton);
    this->bottomLayout->addWidget(this->defaultFontButton);
    this->bottomLayout->addWidget(this->cancelButton);

    this->fontFamilyPicker->setLayout(this->fontFamilyLayout);
    this->fontWeightPicker->setLayout(this->fontWeightLayout);
    this->fontSizePicker->setLayout(this->fontSizeLayout);
    this->bottomWidget->setLayout(this->bottomLayout);

    this->firstLineLayout = new QHBoxLayout();
    this->firstLineLayout->addWidget(this->fontFamilyPicker);
    this->firstLineLayout->addWidget(this->fontWeightPicker);
    this->firstLineLayout->addWidget(this->fontSizePicker);
    this->firstLineWidget->setLayout(this->firstLineLayout);

    this->mainLayout = new QVBoxLayout();
    this->mainLayout->addWidget(this->firstLineWidget);
    this->mainLayout->addWidget(this->bottomWidget);
    this->setLayout(this->mainLayout);

    this->setWindowTitle("MyEditor - FontSetter");
    this->setWindowIcon(QIcon(":/Images/Celestia.ico"));
    this->initLists();
    this->setWindowFlags(Qt::Dialog);

    connect(this->fontSizeInput, &QLineEdit::textEdited, this, &FontSetter::checkInput);

    connect(this->fontFamilyList, &QListWidget::itemClicked, this, &FontSetter::updateFontFamilyInput);
    connect(this->fontSizeList, &QListWidget::itemClicked, this, &FontSetter::updateFontSizeInput);
    connect(this->fontWeightList, &QListWidget::itemClicked, this, &FontSetter::updateFontWeightInput);

    connect(this->useItalicCheckBox, &QCheckBox::clicked, this, &FontSetter::changeUseItalic);
    connect(this->confirmButton, &QPushButton::clicked, this, &FontSetter::setNewFontAndExit);
    connect(this->applyButton, &QPushButton::clicked, this, &FontSetter::setNewFont);
    connect(this->defaultFontButton, &QPushButton::clicked, this, &FontSetter::useDefaultOpts);
    connect(this->cancelButton, &QPushButton::clicked, this, &FontSetter::exitOnly);
}

void FontSetter::getFontOpts(std::string& fontFamily, int& fontSize, QFont::Weight& fontWeight, bool& useItalic) {
    this->fontFamily = &fontFamily;
    this->fontSize = &fontSize;
    this->fontWeight = &fontWeight;
    this->useItalic = &useItalic;

    this->fontFamilyInput->setText(fontFamily.c_str());
    this->fontSizeInput->setText(QString::number(fontSize));
    this->fontWeightInput->setText(FontSetter::fontWeight2Str(fontWeight));

    this->useItalicCheckBox->setChecked(useItalic);
}

void FontSetter::getDefaultFontOpts(const char* fontFamily, const int& fontSize, const QFont::Weight& fontWeight, const bool& useItalic) {
    this->defaultFontFamily = fontFamily;
    this->defaultFontSize = fontSize;
    this->defaultFontWeight = fontWeight;
    this->defaultUseItalic = useItalic;

    this->defaultItemFont = QFont(this->defaultFontFamily, this->defaultFontSize, this->defaultFontWeight, this->defaultUseItalic);
    this->changeItemsFont();
}

const char* FontSetter::fontWeight2Str(const QFont::Weight fontWeight) {
    if (fontWeight == QFont::ExtraBold)
        return "ExtraBold";
    if (fontWeight == QFont::Bold)
        return "Bold";
    if (fontWeight == QFont::Thin)
        return "Thin";
    if (fontWeight == QFont::Light)
        return "Light";
    if (fontWeight == QFont::ExtraLight)
        return "ExtraLight";
    return "Normal";
}

QFont::Weight FontSetter::str2FontWeight(std::string str) {
    if (str == "ExtraBold")
        return QFont::ExtraBold;
    if (str == "Bold")
        return QFont::Bold;
    if (str == "Thin")
        return QFont::Thin;
    if (str == "Light")
        return QFont::Light;
    if (str == "ExtraLight")
        return QFont::ExtraLight;
    return QFont::Normal;
}

void FontSetter::setNewFontAndExit() {
    if (this->setNewFont(true))
        emit this->sendFontOptsAndExit();
}

void FontSetter::checkInput() {
    bool isFine = true;
    if (this->fontSizeInput->hasAcceptableInput()) {
        this->fontSizeLabel->setText("Font Size");
    } else {
        this->fontSizeLabel->setText("Font Size (!)");
        isFine = false;
    }
    this->confirmButton->setEnabled(isFine);
}

void FontSetter::useDefaultOpts() {
    this->fontFamilyInput->setText(this->defaultFontFamily);
    this->fontWeightInput->setText(FontSetter::fontWeight2Str(this->defaultFontWeight));
    this->fontSizeInput->setText(QString::number(this->defaultFontSize));
    this->setNewFont();
    this->normalStatus();
}

void FontSetter::normalStatus() {
    this->fontFamilyLabel->setText("Font Family");
    this->fontWeightLabel->setText("Font Weight");
    this->fontSizeLabel->setText("Font Size");
    this->confirmButton->setEnabled(true);
}

void FontSetter::changeItemsFont() {
    this->fontFamilyLabel->setFont(this->defaultItemFont);
    this->fontSizeLabel->setFont(this->defaultItemFont);
    this->fontWeightLabel->setFont(this->defaultItemFont);

    this->fontFamilyInput->setFont(this->defaultItemFont);
    this->fontSizeInput->setFont(this->defaultItemFont);
    this->fontWeightInput->setFont(this->defaultItemFont);

    this->fontFamilyList->setFont(this->defaultItemFont);
    this->fontSizeList->setFont(this->defaultItemFont);
    this->fontWeightList->setFont(this->defaultItemFont);

    this->useItalicLabel->setFont(this->defaultItemFont);
    this->useItalicCheckBox->setFont(this->defaultItemFont);
    this->confirmButton->setFont(this->defaultItemFont);
    this->applyButton->setFont(this->defaultItemFont);
    this->defaultFontButton->setFont(this->defaultItemFont);
    this->cancelButton->setFont(this->defaultItemFont);
}

void FontSetter::initLists() {
    this->fontWeightStringList.append("ExtraBold");
    this->fontWeightStringList.append("Bold");
    this->fontWeightStringList.append("Normal");
    this->fontWeightStringList.append("Thin");
    this->fontWeightStringList.append("Light");
    this->fontWeightStringList.append("ExtraLight");
    this->fontWeightList->addItems(this->fontWeightStringList);
    this->fontFamilyList->addItems(this->fontFamilies);
    for (int i = 1; i <= 128; ++ i)
        this->fontSizeStringList.append(QString::number(i));
    this->fontSizeList->addItems(this->fontSizeStringList);

    this->fontFamilyCompleter = new QCompleter(this->fontFamilies);
    this->fontFamilyCompleter->setFilterMode(Qt::MatchContains);
    this->fontFamilyInput->setCompleter(this->fontFamilyCompleter);

    this->fontWeightCompleter = new QCompleter(this->fontWeightStringList);
    this->fontWeightCompleter->setFilterMode(Qt::MatchContains);
    this->fontWeightInput->setCompleter(this->fontWeightCompleter);

    this->fontSizeCompleter = new QCompleter(this->fontSizeStringList);
    this->fontSizeCompleter->setFilterMode(Qt::MatchContains);
    this->fontSizeInput->setCompleter(this->fontSizeCompleter);
}

void FontSetter::updateFontFamilyInput() {
    this->fontFamilyInput->setText(this->fontFamilyList->currentItem()->text());
    this->setNewFont();
}

void FontSetter::updateFontWeightInput() {
    this->fontWeightInput->setText(this->fontWeightList->currentItem()->text());
    this->setNewFont();
}

void FontSetter::updateFontSizeInput() {
    this->fontSizeInput->setText(this->fontSizeList->currentItem()->text());
    this->setNewFont();
}

bool FontSetter::setNewFont(bool isCalled) {
    QList<QListWidgetItem*> ffList = this->fontFamilyList->findItems(this->fontFamilyInput->text(), Qt::MatchExactly);
    if (ffList.length()) {
        *(this->fontFamily) = this->fontFamilyInput->text().toStdString();
    } else if (this->fontFamilyList->count()) {
        QMessageBox::warning(
                    this,
                    "Invalid font family",
                    "Please check if the spelling of font family is correct and if it exists in the font list.");
        return false;
    }
    QList<QListWidgetItem*> fwList = this->fontWeightList->findItems(this->fontWeightInput->text(), Qt::MatchExactly);
    if (fwList.length()) {
        *(this->fontWeight) = FontSetter::str2FontWeight(this->fontWeightInput->text().toStdString());
    } else if (this->fontWeightList->count()) {
        QMessageBox::warning(
                    this,
                    "Invalid font weight",
                    "Please check if the spelling of font weight is correct and if it exists in the font list.");
        return false;
    }
    *(this->fontSize) = int(this->fontSizeInput->text().toFloat());
    if (!isCalled)
        emit this->sendFontOpts();
    return true;
}

void FontSetter::changeUseItalic() {
    *(this->useItalic) = !(*(this->useItalic));
    this->setNewFont();
}

FontSetter::~FontSetter() {}
